package com.tool;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import com.tool.util.DiskUtils;

/**
 * License校验过程
 * 
 * @author Evan.Hu
 * 
 */
public class LicenseMgmt {
	private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
	/**
	 * 工作空间所在盘的序列号
	 */
	private static String DRIVER_SN = null;
	/**
	 * 工作电脑名
	 */
	private static String COMPUTER_NAME = null;
	/**
	 * license文本内容
	 */
	private static String[] licenseData = null;
	/**
	 * 文件最后修改时间
	 */
	private static long lastModifiedTime = 0L;
	/**
	 * 持久层文件路径
	 */
	private static String FILE_PATH = "./config/License.p";

	static {
		String userDir = System.getProperty("user.dir");
		DRIVER_SN = DiskUtils.getSerialNumber(userDir.substring(0, 1));
		COMPUTER_NAME = System.getenv().get("COMPUTERNAME");
	}

	/**
	 * 检查是否具有License
	 */
	public static boolean isLicenseValid() {
		// 当返回8位日期数据时表示License有效
		return getValidEndDate().length() == 8;
	}

	/**
	 * 引入License文件
	 * 
	 * @param file
	 */
	public static void importLicenseData(String file) {

		BufferedInputStream inBuff = null;
		BufferedOutputStream outBuff = null;
		try {
			// 新建文件输入流并对它进行缓冲
			inBuff = new BufferedInputStream(new FileInputStream(file));

			// 新建文件输出流并对它进行缓冲
			outBuff = new BufferedOutputStream(new FileOutputStream(FILE_PATH));

			// 缓冲数组
			byte[] b = new byte[1024 * 5];
			int len;
			while ((len = inBuff.read(b)) != -1) {
				outBuff.write(b, 0, len);
			}
			// 刷新此缓冲的输出流
			outBuff.flush();
		} catch (Exception e) {
			throw new RuntimeException("引入文件出错");
		} finally {
			// 关闭流
			if (inBuff != null)
				try {
					inBuff.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			if (outBuff != null)
				try {
					outBuff.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}

		loadLicenseData();
	}

	/**
	 * 获取本机特征码
	 * 
	 * @return
	 */
	public static String getLocalMacCode() {
		String macCode = null;
		try {
			macCode = encryptData(COMPUTER_NAME + "||" + DRIVER_SN);
		} catch (Exception e) {
			macCode = "获取本机特征码失败";
		}
		return macCode;
	}

	/**
	 * 获取License失效时间
	 * 
	 * @return
	 */
	public static String getValidEndDate() {
		String validEndDate = null;
		try {
			loadLicenseData();
			if (COMPUTER_NAME.equals(licenseData[0]) && DRIVER_SN.equals(licenseData[1])) {
				if (Integer.valueOf(licenseData[2]) >= Integer.valueOf(SIMPLE_DATE_FORMAT.format(new Date()))) {
					validEndDate = licenseData[2];
				} else {
					validEndDate = "License已失效,请重新申请License.当前License失效日期:" + licenseData[2];
				}
			} else {
				validEndDate = "特征码不匹配,请重新申请License";
			}
		} catch (RuntimeException e) {
			validEndDate = e.getMessage();
		} catch (Exception e) {
			validEndDate = "License无效";
		}
		return validEndDate;
	}

	/**
	 * @param str
	 * @return
	 */
	private static String[] decode(String str) {
		if (str == null)
			return null;
		String[] vs = str.split("\\|\\|");
		if (vs.length != 3)
			throw new RuntimeException("License文件信息不完整，请联系管理员");

		return vs;
	}

	/**
	 * @param input
	 * @return
	 * @throws Exception
	 */
	private static String encryptData(String input) throws Exception {

		SecureRandom sr = new SecureRandom();
		byte rawKeyData[] = "HIJKLMNO".getBytes();
		DESKeySpec dks = new DESKeySpec(rawKeyData);

		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
		SecretKey key = keyFactory.generateSecret(dks);

		Cipher c = Cipher.getInstance("DES");
		c.init(Cipher.ENCRYPT_MODE, key, sr);
		byte[] cipherByte = c.doFinal(input.getBytes());
		String dec = new BASE64Encoder().encode(cipherByte);
		// 保证不存在换行的问题
		return dec.replaceAll("\r\n", "||");

	}

	/**
	 * @param input
	 * @return
	 * @throws Exception
	 */
	private static String decryptData(String input) throws Exception {
		// 将密文 中存在的换行还原回去
		byte[] dec = new BASE64Decoder().decodeBuffer(input.replaceAll("\\|\\|", "\r\n"));

		SecureRandom sr = new SecureRandom();
		byte rawKeyData[] = "HIJKLMNO".getBytes();

		DESKeySpec dks = new DESKeySpec(rawKeyData);

		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");

		SecretKey key = keyFactory.generateSecret(dks);

		Cipher c = Cipher.getInstance("DES");
		c.init(Cipher.DECRYPT_MODE, key, sr);
		byte[] clearByte = c.doFinal(dec);

		return new String(clearByte);

	}

	/**
	 * 加载数据
	 */
	private static void loadLicenseData() {
		File licFile = new File(FILE_PATH);
		if (!licFile.exists()) {
			throw new RuntimeException("License文件不存在，请联系管理员");
		}
		if (lastModifiedTime != licFile.lastModified()) {
			// 文件未更改过，不需要重新加载
			BufferedReader br = null;
			try {
				br = new BufferedReader(new InputStreamReader(new FileInputStream(FILE_PATH)));
				// 先清除数据
				licenseData = null;
				String line;
				while ((line = br.readLine()) != null) {
					licenseData = decode(decryptData(line));
					break;
				}

				if (licenseData == null) {
					throw new RuntimeException("License文件信息不完整，请联系管理员");
				}

				lastModifiedTime = licFile.lastModified();
			} catch (RuntimeException ee) {
				throw ee;
			} catch (Exception ee) {
				ee.printStackTrace();
				throw new RuntimeException("License文件信息不完整，请联系管理员");
			} finally {
				try {
					if (br != null)
						br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	private static String genLicenseData(String encryptMacCode, int validMonth) {
		String macCode = null;
		try {
			macCode = decryptData(encryptMacCode);
		} catch (Exception e) {
			return "特征码无效";
		}
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.MONTH, validMonth);
		String validDateStr = SIMPLE_DATE_FORMAT.format(cal.getTime());
		try {
			return encryptData(macCode + "||" + validDateStr);
		} catch (Exception e) {
			return "生成License文件失败";
		}
	}

	public static void main(String[] args) throws Exception {
		// 生成运行时6个月有效期License数据,拷贝控制台输出内容保存至文件后，可通过导入License文件功能按钮
		String licenseData = genLicenseData(getLocalMacCode(), 6);
		System.out.println(licenseData);
		System.out.println(decryptData(licenseData));
	}

}
